package pers.mor.tomcat.servlet;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.LogFactory;
import pers.mor.tomcat.config.WebXML;
import pers.mor.tomcat.http.Constant;
import pers.mor.tomcat.http.Request;
import pers.mor.tomcat.http.Response;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;

public class DefaultServlet extends HttpServlet {

    private DefaultServlet() {
    }

    private static DefaultServlet servlet;

    public static DefaultServlet instance(){
        if (servlet == null) {
            servlet = new DefaultServlet();
        }
        return servlet;
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Request request = (Request)req;
        Response response = (Response)resp;

        String uri = request.getUri();
        if (uri.equals("/")) {
            String[] filenames = WebXML.welcomeFilenames();

            boolean well = false;
            for (String filename : filenames) {
                File file = new File(Constant.rootFolder, filename);
                well = ifReadingFileGoesWell(response, file);
                if (well == true) {
                    break;
                }
            }

            if (well == false) {
                File file = new File(Constant.rootFolder, "index.html");
                ifReadingFileGoesWell(response, file);
            }
        } else {
            if (uri.equals("/500.html")) {
                // 模拟实际web项目导致的服务器异常。
                throw new RuntimeException("用于测试 500 错误的 Server 服务器异常。");
            }
            if (uri.equals("/timeConsume.html")) {
                // 模拟实际web项目响应时间，用于测试多线程处理请求。
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            String fileName = StrUtil.removePrefix(uri, "/");
            File file = new File(request.getRealPath(fileName));

            boolean well = ifReadingFileGoesWell(response, file);

            if (well == false) {
                String response404 = StrUtil.format(Constant.textFormat_404, uri, uri);
                response.getWriter().print(response404);
                response.setStatus(Constant.CODE_404);
                return;
            }
        }
        response.setStatus(Constant.CODE_200);
    }

    private static boolean ifReadingFileGoesWell(Response response, File file) {
        if (file.exists() && file.isFile()) {
            try{
                String fileExtension = StrUtil.subAfter(file.getName(), ".", true);
                String mimeType = WebXML.getMimeType(fileExtension);
                response.setContentType(mimeType);
                response.setCharacterEncoding(StandardCharsets.UTF_8.toString());

                byte[] bytes = readFile(file);
                response.setBody(bytes);

                return true;
            } catch(IOException e) {
                LogFactory.get().error(e);
                return false;
            }
        }
        return false;
    }

    private static byte[] readFile(File file) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        FileInputStream fileInputStream = new FileInputStream(file);
        while (true) {
            int len = fileInputStream.read(buffer);
            if ((len == -1)) {
                break;
            }
            if (len < 1024) {
                byte[] b = new byte[len];
                for (int i = 0; i < len; i++) {
                    b[i] = buffer[i];
                }
                buffer = b;
            }
            baos.write(buffer);
        }
        fileInputStream.close();
        return baos.toByteArray();
    }
}
